package server

import (
	"context"
	"ctfo-platform-go/server/model"
	"fmt"
	"net/http"
	"reflect"
	"strconv"

	"github.com/go-chi/render"
)

type contextKey struct{}

var (
	pageContextKey = &contextKey{}
	bindReqKey     = &contextKey{}
)

func paginate(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ctx := r.Context()
		urlQuery := r.URL.Query()
		var pageParam model.PageParam
		pageSize, _ := strconv.Atoi(urlQuery.Get("pageSize"))
		pageNo, _ := strconv.Atoi(urlQuery.Get("pageNo"))
		if pageSize == 0 {
			pageSize = 10
		}
		if pageNo == 0 {
			pageNo = 1
		}
		pageParam.PageNo = pageNo
		pageParam.PageSize = pageSize
		r = r.WithContext(context.WithValue(ctx, pageContextKey, pageParam))
		next.ServeHTTP(w, r)
	})
}

func bindRequestBody(obj render.Binder) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			data, err := createInstance(obj)
			if err != nil {
				render.Render(w, r, errData(fmt.Errorf("create instance error:%w", err)))
				return
			}
			binder := data.(render.Binder)

			err = render.Bind(r, binder)
			if err != nil {
				render.Render(w, r, errData(fmt.Errorf("bind data error:%w", err)))
				return
			}
			ctx := r.Context()
			r = r.WithContext(context.WithValue(ctx, bindReqKey, data))
			next.ServeHTTP(w, r)

		}

		return http.HandlerFunc(fn)
	}
}

func createInstance(obj render.Binder) (any, error) {
	objType := reflect.TypeOf(obj)

	// 如果是指针，则获取指向的类型
	if objType.Kind() == reflect.Ptr {
		objType = objType.Elem()
	}

	// 如果是结构体，则创建新实例, 并返回指针
	if objType.Kind() == reflect.Struct {
		return reflect.New(objType).Interface(), nil
	}

	// 如果是 map，则创建新实例
	if objType.Kind() == reflect.Map {
		return reflect.MakeMap(objType).Interface(), nil
	}

	return nil, fmt.Errorf("unsupported type: %T", obj)
}
